﻿using LightCAD.MathLib;
namespace QdArch
{
    public class QdStair : LcComponent
    {
        public static Shape2dProvider ShapeProvider;
        public static ParameterSetDefinition ParamsDefinition;
        static QdStair()
        {
            ShapeProvider = Shape2dManager.LoadProvider(ArchCategory.Stair.ToString());

            ParamsDefinition = new ParameterSetDefinition() {
                 new ParameterDefinition
                 {
                     Name = "StepHeight",
                     DataType= LcDataType.Double,
                 },
                 new ParameterDefinition
                 {
                     Name = "StepWidth",
                      DataType= LcDataType.Double,
                 },  
                new ParameterDefinition
                 {
                     Name = "StepNum",
                      DataType= LcDataType.Int,
                 }, 
                new ParameterDefinition
                 {
                     Name = "LadderWidth",
                      DataType= LcDataType.Double,
                 },
                 new ParameterDefinition
                 {
                     Name = "PlatWidth",
                     DataType= LcDataType.Double,
                 }, 
                new ParameterDefinition
                 {
                     Name = "PlatLen",
                     DataType= LcDataType.Double,
                 },
                 new ParameterDefinition
                 {
                     Name = "PlatThickness",
                     DataType= LcDataType.Double,
                 },
                 new ParameterDefinition
                 {
                     Name = "SlabThickness",
                     DataType= LcDataType.Double,
                 },
            };

        }
        public QdStair()
        {
            base.Category = ArchCategory.Stair.ToString();
            this.Uuid = Guid.NewGuid().ToString();
        }
        public QdStair(string subCategory, string name) : this()
        {
            base.SubCategory = subCategory;
            base.Name = name;
            this.Shape2D = ShapeProvider.Shapes.GetShape(name);
        }
    }
    public class QdStairRef : LcComponentInstance, IElement3D 
    {
        public object Rt3DAction { get; set; } = StairAction3D.Instance;
        public LcParameterSet Parameters { get; set; }
        public double StepHeight { get => Convert.ToDouble(Parameters["StepHeight"]);set => Set("StepHeight", value); } 
        public double StepWidth { get => Convert.ToDouble(Parameters["StepWidth"]); set => Set("StepWidth", value); }
        public int StepNum { get => Convert.ToInt32(Parameters["StepNum"]); set => Set("StepNum", value); }
        public double LadderWidth { get => Convert.ToDouble(Parameters["LadderWidth"]); set => Set("LadderWidth", value); }
        public double PlatWidth { get => Convert.ToDouble(Parameters["PlatWidth"]); set => Set("PlatWidth", value); }
        public double PlatLen { get => Convert.ToDouble(Parameters["PlatLen"]); set => Set("PlatLen", value); }
        public double PlatThickness { get => Convert.ToDouble(Parameters["PlatThickness"]); set => Set("PlatThickness", value); }
        public double SlabThickness { get => Convert.ToDouble(Parameters["SlabThickness"]); set => Set("SlabThickness", value); }
        
        public QdStair stair { get; set; }

        public QdStairRef()
        {
            this.Type = ArchElementType.Stair;
        }
        public override Box2 GetBoundingBox()
        {
            if (this.Parameters == null || this.Parameters.Values.Length == 0)
            {
                return Box2.Empty;
            }
            var width = this.StepNum * this.StepWidth + this.PlatWidth;
            var len = this.PlatLen;
            var points = new Vector2[] {new Vector2(),new Vector2(len,0),new Vector2(len,width),new Vector2(0,width) };
            for (int i = 0; i < 4; i++)
            {
                points[i] = this.Matrix.MultiplyPoint(points[i]);
            }
            var box2d=new Box2().MakeEmpty();
            box2d=box2d.ExpandByPoints(points);
            return box2d;

        }

        private List<Curve2d> _shapeCurves;
        public List<Curve2d> ShapeCurves
        {
            get
            {
                if (_shapeCurves == null)
                {
                    _shapeCurves = this.stair?.Shape2D?.Generate(this.Parameters);
                }
                return _shapeCurves;
            }
        }

        public void ResetShapeCurves()
        {
            this._shapeCurves = this.stair?.Shape2D?.Generate(this.Parameters);
        }

        public override bool IntersectWithBox(Polygon2d testPoly, List<RefChildElement> intersectChildren = null)
        {
            Box2 thisBox = this.BoundingBox;
            if (!thisBox.IntersectsBox(testPoly.BoundingBox))
            {
                return false;
            }
            return true;
        }
        public override bool IncludedByBox(Polygon2d testPoly, List<RefChildElement> includedChildren = null)
        {
            Box2 thisBox = this.BoundingBox;
            if (!testPoly.BoundingBox.ContainsBox(thisBox))
            {
                return false;
            }
            return true;
        }
        public void Set(string name,object val) 
        {
            OnPropertyChangedBefore(name, this.Parameters[name], val);
            this.Parameters[name] = val;
            OnPropertyChangedAfter(name, this.Parameters[name], val);
        }
        public override LcElement Clone()
        {
            var clone = Document.CreateObject<QdStairRef>();
            clone.Copy(this);
            clone.Initilize(this.Document);
            return clone;
        }

        public override void Copy(LcElement src)
        {
            base.Copy(src);
            var stairRef = (QdStairRef)src;
            this.Parameters = QdStair.ParamsDefinition.New();
            this.stair = stairRef.stair;
            var count = stairRef.Parameters.Values.Count();
            for (int i = 0; i < count; i++)
            {
                this.Parameters[i] = stairRef.Parameters[i];
            }

        }

        public override void WriteProperties(Utf8JsonWriter writer, JsonSerializerOptions soptions)
        {
            base.WriteProperties(writer, soptions);

            writer.WriteString("StairId", this.stair.Uuid);
            writer.WriteNumberProperty(nameof(StepHeight), this.StepHeight);
            writer.WriteNumberProperty(nameof(StepWidth), this.StepWidth);
            writer.WriteNumberProperty(nameof(StepNum), this.StepNum);
            writer.WriteNumberProperty(nameof(LadderWidth), this.LadderWidth);
            writer.WriteNumberProperty(nameof(PlatWidth), this.PlatWidth);
            writer.WriteNumberProperty(nameof(PlatLen), this.PlatLen);
            writer.WriteNumberProperty(nameof(PlatThickness), this.PlatThickness);
            writer.WriteNumberProperty(nameof(SlabThickness), this.SlabThickness);
        }

        public override void ReadProperties(ref JsonElement jele)
        {
            base.ReadProperties(ref jele);

            var stairId = jele.ReadStringProperty("StairId");
            var cpt = this.Document.Components[stairId];
            var stair = new QdStair(cpt.SubCategory, cpt.Name);
            stair.Uuid = stairId;
            this.stair = stair;
            this.Document.Components.Remove(stairId);
            this.Document.Components.Add(stair);

            this.Parameters = QdStair.ParamsDefinition.New();
            this.StepHeight = jele.ReadDoubleProperty(nameof(this.StepHeight));
            this.StepWidth = jele.ReadDoubleProperty(nameof(this.StepWidth));
            this.StepNum = jele.ReadIntProperty(nameof(this.StepNum));
            this.LadderWidth = jele.ReadDoubleProperty(nameof(this.LadderWidth));
            this.PlatWidth = jele.ReadDoubleProperty(nameof(this.PlatWidth));
            this.PlatLen = jele.ReadDoubleProperty(nameof(this.PlatLen));
            this.PlatThickness = jele.ReadDoubleProperty(nameof(this.PlatThickness));
            this.SlabThickness = jele.ReadDoubleProperty(nameof(this.SlabThickness));
        }
    }
}
